using System;
namespace fuzzyKittenVNC
{
	namespace VNCMessages
	{
		public interface VNCClientMessage : VNCMessage{
		}
		
		public class ClientInit : VNCClientMessage {
			public bool isExclusive = false;
			
			public ClientInit(bool exclusive) {
				this.isExclusive =  exclusive;			
			}
			
			public byte[] getMessage() {
				byte[] msg = {this.isExclusive ? (byte) 0x01 : (byte) 0x00};
				return msg;
			}	
		}
	
		public class SetEncodings : VNCClientMessage {
			public byte msgType = 0x02;
			public int[] encodings = {		
			//	7,
/*				-258,
				-223,*/
			//	1464686185,
			//	-239, // PseudoCursor
			/*	-240,
				-257,*/
			//	16, // ZRLE
			//	5,	// Hextile  // Desktopsize change is supported	7, // tight
			//	2, // RRE 
			//	1, // CopyRect
				0 // RAW
				

			};
			
			public byte[] getMessage() {
				byte[] msg = new byte[4+4*encodings.Length];	
				msg[0] = 0x02;
				msg[1] = 0x00;
				
				msg[2] = (byte) (encodings.Length>>8&0xff);
				msg[3] = (byte) (encodings.Length&0xff);
				
				for(int i=0;i<encodings.Length;i++) {

					// switch to big endian
					msg[(i*4)+4] = (byte) (encodings[i]>>24&0xff);
					msg[(i*4)+5] = (byte) (encodings[i]>>16&0xff);
					msg[(i*4)+6] = (byte) (encodings[i]>>8&0xff);
					msg[(i*4)+7] = (byte) (encodings[i]&0xff);					

				}
			

				return msg;
			}
		}
		
		public class FrameBufferUpdateRequest : VNCClientMessage {
			public byte msgType = 0x03;
			public bool increment = false;
			public uint x;
			public uint y;
			public uint w;
			public uint h;
			
			public FrameBufferUpdateRequest(bool increment,uint x,uint y, uint h, uint w) {
				this.increment = increment;
				this.x = x;
				this.y = y;
				this.h = h;
				this.w = w;
			}
			
			public byte[] getMessage() {
				byte[] msg = {
					(byte) (0x03),
					(byte) (this.increment ? 0x01 : 0x00),
							
					(byte) (this.x>>8&0xff),
					(byte) (this.x&0xff), 
					
					(byte) (this.y>>8&0xff),
					(byte) (this.y&0xff), 
				
					(byte) (this.h>>8&0xff),
					(byte) (this.h&0xff), 	
					
					(byte) (this.w>>8&0xff),
					(byte) (this.w&0xff) 

				};
				return msg;
			}
		}
		
		public class KeyEvent : VNCClientMessage {
			public uint key;
			public bool downFlag;
			
			public KeyEvent(bool down,uint key) {
				this.downFlag = down;
				this.key = key;
			}
			
			public byte[] getMessage() {
				byte[] msg = {
					(byte) 0x04,
					(byte) (this.downFlag ? 0x01 : 0x00),
					(byte) 0x00,
					(byte) 0x00,
					(byte) (this.key>>24&0xff), 
					(byte) (this.key>>16&0xff),
					(byte) (this.key>>8&0xff), 
					(byte) (this.key&0xff)
				};

				return msg;
			}
		}
		
		public class PointerEvent : VNCClientMessage {
			byte btnMask;
			int x;
			int y;
			
			public PointerEvent(int x,int y,byte btnMask) {
				this.btnMask = btnMask;
				this.x = x;
				this.y = y;
			}
			
			public byte[] getMessage() {
				byte[] msg = {
					(byte) 0x05,
					(byte) (this.btnMask),
					
					(byte) (this.x>>8&0xff),
					(byte) (this.x&0xff),
					
					(byte) (this.y>>8&0xff),
					(byte) (this.y&0xff)

				};
				return msg;
			}
		}
		
		public class ClientCutText : VNCClientMessage {
			int textLength;
			byte[] text;
			
			public ClientCutText(string text) {
				this.textLength = text.Length;
				this.text = System.Text.Encoding.ASCII.GetBytes(text);
			}
			
			public byte[] getMessage() {
				byte[] msg = new byte[8+this.textLength];
				byte[] msgBegin = {
					(byte) 0x06,
					0x00,0x00,0x00,
					(byte) (this.textLength&0xff), 
					(byte) (this.textLength>>8&0xff),
					(byte) (this.textLength>>16&0xff),
					(byte) (this.textLength>>24&0xff)
				};
				Array.Copy(msgBegin,msg,8);
				Array.Copy(text,0,msg,8,this.textLength);
				return msg;
			}
		}

		
		public class SetPixelFormat : VNCClientMessage  {
			public byte msgType = 0x00;
			public int bits_per_pixel;
			public int depth;
			public bool bigEndianFlag;
			public bool trueColorFlag;
			public int redMax;
			public int greenMax;
			public int blueMax;
			public int redShift;
			public int greenShift;
			public int blueShift;
			
			public SetPixelFormat(int bpp,int depth,bool bigEndian,bool trueColor,int rm, int gm, int bm, int redShift, int greenShift, int blueShift) {
				this.bits_per_pixel = bpp;
				this.depth = depth;
				this.bigEndianFlag = bigEndian;
				this.trueColorFlag = trueColor;
				this.redMax = rm;
				this.greenMax = gm;
				this.blueMax = bm;
				this.redShift = redShift;
				this.greenShift = greenShift;
				this.blueShift = blueShift;
			}
			
			public byte[] getMessage() {
				byte[] msg = new byte[20];
				msg[0] = this.msgType;
				msg[1] = (byte) 0x00;
				msg[2] = (byte) this.bits_per_pixel;
				msg[3] = (byte) this.depth;
				msg[4] = (byte) (this.bigEndianFlag ? 0x00 : 0x01);
				msg[5] = (byte) (this.trueColorFlag ? 0x00 : 0x01);
				
				msg[7] = (byte) (this.redMax & 0xff);
				msg[6] = (byte) (this.redMax >> 8 & 0xff);						
				msg[9] = (byte) (this.greenMax & 0xff);
				msg[8] = (byte) (this.greenMax >> 8 & 0xff);
				msg[11] = (byte) (this.blueMax & 0xff);
				msg[10] = (byte) (this.blueMax >> 8 & 0xff);
				
				msg[12] = (byte) (this.redShift);
				msg[13] = (byte) (this.greenShift);
				msg[14] = (byte) (this.blueShift);				

				return msg;
			}
			
		}
	}
}

